import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';

describe('Entity Relationship Diagram', () => {
  it('should render a simple ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with a recursive relationship', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||..o{ CUSTOMER : refers
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with multiple relationships between the same two entities', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||--|{ ADDRESS : "invoiced at"
        CUSTOMER ||--|{ ADDRESS : "receives goods at"
      `,
      { logLevel: 1 }
    );
  });

  it('should render a cyclical ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        A ||--|{ B : likes
        B ||--|{ C : likes
        C ||--|{ A : likes
      `,
      { logLevel: 1 }
    );
  });

  it('should render a not-so-simple ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER }|..|{ DELIVERY-ADDRESS : has
        CUSTOMER ||--o{ ORDER : places
        CUSTOMER ||--o{ INVOICE : "liable for"
        DELIVERY-ADDRESS ||--o{ ORDER : receives
        INVOICE ||--|{ ORDER : covers
        ORDER ||--|{ ORDER-ITEM : includes
        PRODUCT-CATEGORY ||--|{ PRODUCT : contains
        PRODUCT ||--o{ ORDER-ITEM : "ordered in"
      `,
      { logLevel: 1 }
    );
  });

  it('should render multiple ER diagrams', () => {
    imgSnapshotTest(
      [
        `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
        `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      ],
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with blank or empty labels', () => {
    imgSnapshotTest(
      `
    erDiagram
        BOOK }|..|{ AUTHOR : ""
        BOOK }|..|{ GENRE : " "
        AUTHOR }|..|{ GENRE : "  "
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagrams when useMaxWidth is true (default)', () => {
    renderGraph(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { er: { useMaxWidth: true } }
    );
    cy.get('svg').should((svg) => {
      expect(svg).to.have.attr('width', '100%');
      // expect(svg).to.have.attr('height', '465');
      const style = svg.attr('style');
      expect(style).to.match(/^max-width: [\d.]+px;$/);
      const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
      // use within because the absolute value can be slightly different depending on the environment ±6%
      expect(maxWidthValue).to.be.within(140 * 0.96, 140 * 1.06);
    });
  });

  it('should render an ER when useMaxWidth is false', () => {
    renderGraph(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { er: { useMaxWidth: false } }
    );
    cy.get('svg').should((svg) => {
      const width = parseFloat(svg.attr('width'));
      // use within because the absolute value can be slightly different depending on the environment ±6%
      expect(width).to.be.within(140 * 0.96, 140 * 1.06);
      // expect(svg).to.have.attr('height', '465');
      expect(svg).to.not.have.attr('style');
    });
  });

  it('should render entities that have no relationships', () => {
    renderGraph(
      `
    erDiagram
        DEAD_PARROT
        HERMIT
        RECLUSE
        SOCIALITE }o--o{ SOCIALITE : "interacts with"
        RECLUSE }o--o{ SOCIALITE : avoids
      `,
      { er: { useMaxWidth: false } }
    );
  });

  it('should render entities with and without attributes', () => {
    renderGraph(
      `
    erDiagram
        BOOK { string title }
        AUTHOR }|..|{ BOOK : writes
        BOOK { float price }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with generic and array attributes', () => {
    renderGraph(
      `
    erDiagram
        BOOK {
          string title
          string[] authors
          type~T~ type
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with length in attributes type', () => {
    renderGraph(
      `
    erDiagram
        CLUSTER {
          varchar(99) name
          string(255) description
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities and attributes with big and small entity names', () => {
    renderGraph(
      `
    erDiagram
        PRIVATE_FINANCIAL_INSTITUTION {
          string name
          int    turnover
        }
        PRIVATE_FINANCIAL_INSTITUTION ||..|{ EMPLOYEE : employs
        EMPLOYEE { bool officer_of_firm }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with attributes that begin with asterisk', () => {
    imgSnapshotTest(
      `
    erDiagram
        BOOK {
          int         *id
          string      name
          varchar(99) summary
        }
        BOOK }o..o{ STORE : soldBy
        STORE {
          int         *id
          string      name
          varchar(50) address
        }
        `,
      { loglevel: 1 }
    );
  });

  it('should render entities with keys', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name PK
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          float price
          string author FK
          string title PK
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with comments', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name "comment"
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          string author
          string title "author comment"
          float price "price comment"
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with keys and comments', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name PK "comment"
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          string description
          float price "price comment"
          string title PK "title comment"
          string author FK
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with aliases', () => {
    renderGraph(
      `
    erDiagram
      T1 one or zero to one or more T2 : test
      T2 one or many optionally to zero or one T3 : test
      T3 zero or more to zero or many T4 : test
      T4 many(0) to many(1) T5 : test
      T5 many optionally to one T6 : test
      T6 only one optionally to only one T1 : test
      T4 0+ to 1+ T6 : test
      T1 1 to 1 T3 : test
      `,
      { logLevel: 1 }
    );
  });

  it('1433: should render a simple ER diagram with a title', () => {
    imgSnapshotTest(
      `---
title: simple ER diagram
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
`,
      {}
    );
  });

  it('should render entities with entity name aliases', () => {
    imgSnapshotTest(
      `
    erDiagram
      p[Person] {
        varchar(64) firstName
        varchar(64) lastName
      }
      c["Customer Account"] {
        varchar(128) email
      }
      p ||--o| c : has
      `,
      { logLevel: 1 }
    );
  });

  it('should render relationship labels with line breaks', () => {
    imgSnapshotTest(
      `
    erDiagram
      p[Person] {
          string firstName
          string lastName
      }
      a["Customer Account"] {
          string email
      }

      b["Customer Account Secondary"] {
        string email
      }
      
      c["Customer Account Tertiary"] {
        string email
      }
      
      d["Customer Account Nth"] {
        string email
      }

      p ||--o| a : "has<br />one"
      p ||--o| b : "has<br />one<br />two"
      p ||--o| c : "has<br />one<br/>two<br />three"
      p ||--o| d : "has<br />one<br />two<br/>three<br />...<br/>Nth"
      `,
      { logLevel: 1 }
    );
  });

  describe('Include char sequence "graph" in text (#6795)', () => {
    it('has a label with char sequence "graph"', () => {
      imgSnapshotTest(
        `
        erDiagram
          p[Photograph] {
            varchar(12) jobId
            date dateCreated
          }
        `,
        { flowchart: { defaultRenderer: 'elk' } }
      );
    });
  });

  describe('Special characters and numbers syntax', () => {
    it('should render ER diagram with numeric entity names', () => {
      imgSnapshotTest(
        `
        erDiagram
          1 ||--|| ORDER : places
          ORDER ||--|{ 2 : contains
          2 ||--o{ 3.5 : references
        `,
        { logLevel: 1 }
      );
    });

    it('should render ER diagram with "u" character in entity names and cardinality', () => {
      imgSnapshotTest(
        `
        erDiagram
          CUSTOMER ||--|| u : has
          u ||--|| ORDER : places
          PROJECT u--o{ TEAM_MEMBER : "parent"
        `,
        { logLevel: 1 }
      );
    });

    it('should render ER diagram with decimal numbers in relationships', () => {
      imgSnapshotTest(
        `
        erDiagram
          2.5 ||--|| 1.5 : has
          CUSTOMER ||--o{ 3.14 : references
          1.0 ||--|{ ORDER : contains
        `,
        { logLevel: 1 }
      );
    });

    it('should render ER diagram with numeric entity names and attributes', () => {
      imgSnapshotTest(
        `
        erDiagram
          1 {
            string name
            int value
          }
          1 ||--|| ORDER : places
          ORDER {
            float price
            string description
          }
        `,
        { logLevel: 1 }
      );
    });

    it('should render complex ER diagram with mixed special entity names', () => {
      imgSnapshotTest(
        `
        erDiagram
          CUSTOMER ||--o{ 1 : places
          1 ||--|{ u : contains
          1.5
          u ||--|| 2.5 : processes
          2.5 {
            string id
            float value
          }
          u {
            varchar(50) name
            int count
          }
        `,
        { logLevel: 1 }
      );
    });
    it('should render ER diagram with standalone numeric entities', () => {
      imgSnapshotTest(
        `erDiagram
         PRODUCT ||--o{ ORDER-ITEM : has
         1.5
         u
         1
        `,
        { logLevel: 1 }
      );
    });
  });
});
